package com.itany.corejava.util;

import java.io.*;

/**
 * @author 石小俊
 * @date 2023年05月11日 10:23
 * 文件相关工具类
 */
public class FileUtil {

    /**
     * 拷贝文件
     *
     * @param src    源文件
     * @param target 目标文件
     */
    public static void copyFile(File src, File target) {
        try (
                // 将src中的内容读取出来
                InputStream in = new FileInputStream(src);
                // 写入到target中
                OutputStream out = new FileOutputStream(target);
        ) {
            byte[] b = new byte[1024];
            int i = -1;
            while ((i = in.read(b)) != -1) {
                out.write(b, 0, i);
            }
            System.out.println("文件复制成功");
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    /**
     * 拷贝文件
     *
     * @param src    源文件
     * @param target 目标文件
     */
    public static void copyFile(String src, String target) {
        copyFile(new File(src), new File(target));
    }

    /**
     * 将一个目录中所有的文件拷贝到指定目录中
     *
     * @param src    源目录
     * @param target 目标目标
     */
    public static void copyDirectory(String src, String target) {
        File srcFile = new File(src);
        // 获取该目录中所有的文件
        File[] files = srcFile.listFiles();

        // 创建目标目录
        File targetFile = new File(target);
        targetFile.mkdirs();
        for (File file : files) {
            if (file.isFile()) {
                // 当遍历的File对象是一个文件时,则拷贝一份到指定目录中
                // 拷贝的路径是目标目录+分隔符+文件名
                copyFile(file, new File(target + File.separator + file.getName()));
            }
        }
    }

    /**
     * 将一个目录中的文件与子目录递归拷贝到一个指定的目录中
     *
     * @param src
     * @param target
     */
    public static void recursiveCopy(String src, String target) {
        File srcFile = new File(src);
        // 获取该目录中所有的子文件
        File[] files = srcFile.listFiles();

        // 创建目标目录
        File targetFile = new File(target);
        targetFile.mkdirs();

        // 遍历所有子文件
        for (File file : files) {
            // 如果是子目录
            if (file.isDirectory()) {
                // 递归操作,将当前子目录中的资源拷贝到目标目录的子目录中,子目录名与当前目录名一致
                recursiveCopy(file.getAbsolutePath(), target + File.separator + file.getName());
            } else {
                // 如果是文件,则直接复制
                copyFile(file, new File(target, file.getName()));
            }
        }
    }

    /**
     * 拆分文件,将一个文件按照指定大小拆分成多个文件
     * 每一个文件名字为:原名字_index,index从1开始,每次自增1
     * 一个输入流,多个输出流
     *
     * @param path
     * @param length
     */
    public static void splitFile(String path, int length) {
        FileOutputStream out = null;
        FileInputStream in = null;
        try {
            in = new FileInputStream(path);
            // 设置每次读取的字节数
            byte[] b = new byte[length];
            int i = -1;
            // 用于作为拆分的文件的后缀
            int index = 1;
            while ((i = in.read(b)) != -1) {
                // 每读取一个生成一个输出流
                out = new FileOutputStream(path + "_" + index++);
                out.write(b, 0, i);
                // 输出完成之后,将当前开启的输出流关闭
                out.close();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 合并文件,将之前拆分的文件合并为一个文件,将子文件的_index部分删除作为文件名
     * 传入第一个文件,按照该文件的格式将所有格式相同的文件合并
     * 其所有文件的名字均为:文件名_索引号
     * 一个输出流,多个输入流
     *
     * @param path 指定文件的路径
     */
    public static void mergeFile(String path) {
        try {
            // 将传入的文件路径值_包含后面的数字清除
            path = path.substring(0, path.lastIndexOf("_"));
            // 指定一个输出流,用于接收输出的数据
            FileOutputStream out = new FileOutputStream(path);
            // 定义所有合并的子文件的后缀数字
            int index = 1;
            File file = null;
            // 当子文件存在,则进行合并
            while ((file = new File(path + "_" + index++)).exists()) {
                // 定义多个输入流
                FileInputStream in = new FileInputStream(file);
                copyStream(in, out);
                // 关闭当前开启的输入流
                in.close();
                System.out.println(path + "合并成功");
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 合并文件
     *
     * @param firstFile 第一个文件对象
     */
    public static void mergeFile(File firstFile) {
        try {
            String path = firstFile.getAbsolutePath();
            // 将传入的文件路径值_包含后面的数字清除
            path = path.substring(0, path.lastIndexOf("_"));
            // 指定一个输出流,用于接收输出的数据
            FileOutputStream out = new FileOutputStream(path);
            // 定义所有合并的子文件的后缀数字
            int index = 1;
            File file = null;
            // 当子文件存在,则进行合并
            while ((file = new File(path + "_" + index++)).exists()) {
                // 定义多个输入流
                FileInputStream in = new FileInputStream(file);
                copyStream(in, out);
                // 关闭当前开启的输入流
                in.close();
                System.out.println(path + "合并成功");
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void copyStream(FileInputStream in, FileOutputStream out) throws IOException {
        try {
            byte[] b = new byte[1024 * 1024];
            int i = -1;
            while ((i = in.read(b)) != -1) {
                out.write(b, 0, i);
            }
        } catch (IOException e) {
            throw e;
        }
    }

    /**
     * 文件加密
     * 按字节读取,每个字节通过异或操作实现加密
     * 加密后的文件添加.sec后缀
     * @param file
     * @param password
     */
    public static void encoded(File file, int password) {
        try (
                FileInputStream in = new FileInputStream(file);
                FileOutputStream out = new FileOutputStream(file.getAbsoluteFile() + ".sec");
        ) {
            int data = -1;
            while ((data = in.read()) != -1) {
                // 每次只读取一个字节,对于读取的字节通过异或操作进行加密
                // 将加密后的数据写入到新文件中
                out.write(data ^ password);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 文件解密
     * 按字节读取加密后的文件内容,每个字节通过异或操作实现解密
     * 解密后的文件去除.sec后缀
     * @param file
     * @param password
     */
    public static void decoded(File file, int password) {
        try (
                FileInputStream in = new FileInputStream(file);
                FileOutputStream out = new FileOutputStream(file.getAbsolutePath().substring(0, file.getAbsolutePath().lastIndexOf(".")))
        ) {
            int data = -1;
            while ((data = in.read()) != -1) {
                out.write(data ^ password);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
